package uk.ac.glasgow.demosocs.impl.electionmanager;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import uk.ac.glasgow.demosocs.Candidate;
import uk.ac.glasgow.demosocs.Election;
import uk.ac.glasgow.demosocs.ElectionResult;
import uk.ac.glasgow.demosocs.ElectionState;

public class ElectionImpl implements Election{
	private String eid;
	private String name;
	private Date start;
	private Date end;
	private Date openNominations;
	private ElectionState electionState;
	private ElectionResult electionResult;
	private HashMap<String,String> votes;
	private Set<Candidate> candidates;
	
	// Change this? - Need a type?
	private String type;
	
	public ElectionImpl(String n){
		this.name = n;
		this.start = new Date();
	}
	public ElectionImpl(String n, Date startDate){
		this.name = n;
		this.start=startDate;
	}
	public ElectionImpl(String n,String t){
		this.name=n;
		this.type=t;
	}
	public ElectionImpl(String n, Date startDate, String t){
		this.name=n;
		this.start=startDate;
		this.type=t;
	}
	public HashMap<String, String> getVotes() {
		return votes;
	}
	public Date getStart() {
		return start;
	}
	public Date getEnd() {
		return end;
	}
	public Date getOpenNominations() {
		return openNominations;
	}
	public ElectionState getElectionState() {
		return electionState;
	}
	@Override
	public String getEID() {
		// TODO Auto-generated method stub
		return eid;
	}
	@Override
	public ElectionResult getElectionResult() {
		// TODO Auto-generated method stub
		return electionResult;
	}
	@Override
	public Set<Candidate> getCandidates() {
		// TODO Auto-generated method stub
		return null;
	}
	public void publishResults(){
		HashMap<String,Integer> candidateVotes = new HashMap<String,Integer>(); // HashMap to map each candidate to it's total votes.
		String[] setOfVoters = (String[]) votes.keySet().toArray(); //An array of voters
		for(int i=0;i<setOfVoters.length;i++){ // For each voter
			String voterGUID = setOfVoters[i];
			String candidateGUID = votes.get(voterGUID); // Get the candidate that the voter voted for.
			int currentVoteTotal=0; // initialise the vote total to 0
			if(candidateVotes.containsKey(candidateGUID)) // if the candidate has already received votes
				currentVoteTotal = (Integer) candidateVotes.remove(candidateGUID); // get the current vote total
			candidateVotes.put(candidateGUID, ++currentVoteTotal); // add the candidate to the hashmap with it's total votes.
		}
		String[] setOfCandidates = (String[]) candidateVotes.keySet().toArray(); // An array of Election candidates with votes.
		int currentWinningNumberOfVotes=0; //a total variable, recording the current winning vote total.
		ArrayList<String> winningCandidates = new ArrayList<String>(2); // Start with 2 as capacity.
		for(int i=0;i<setOfCandidates.length;i++){ // For each candidate
			String candidateGUID = setOfCandidates[i];
			int candidateVoteTotal = candidateVotes.get(candidateGUID); // Get the GUID and Number of votes.
			if(candidateVoteTotal>currentWinningNumberOfVotes){// if this candidate has more votes than the current winner
				winningCandidates = new ArrayList<String>(2); // Create a new (Capacity 2) arraylist to store the winning Candidates
				winningCandidates.add(candidateGUID); // add this candidate to the winning list
				currentWinningNumberOfVotes=candidateVoteTotal; // This candidate's vote total is winning
			}else if(candidateVoteTotal==currentWinningNumberOfVotes) // if this candidate, equals votes with the current winner
				winningCandidates.add(candidateGUID); // add this candidate to the list
		}
		List<Candidate> publishWinningCandidates = new ArrayList<Candidate>(winningCandidates.size());
		Candidate[] allElectionCandidates = (Candidate[]) this.candidates.toArray(); // Array of all election candidates
		for(int i=0;i<allElectionCandidates.length;i++){ // for each candidate c
			Candidate c = allElectionCandidates[i]; 
			if(winningCandidates.contains(c.getGUID())) // if candidate is a winner
					publishWinningCandidates.add(c); // add to the winning list
		}
		ElectionResult publishElectionResult = new ElectionResultImpl(publishWinningCandidates);
		this.electionResult = publishElectionResult;
		this.electionState=ElectionState.PUBLISHED; // Publish that bad boy and change state of election/
	}
}
